package com.yxsk.relay.job.component.endpoint.log.stream;

import com.yxsk.relay.job.component.common.utils.Assert;
import com.yxsk.relay.job.component.endpoint.exception.log.RelayJobLogException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

/**
 * @Author 11376
 * @CreaTime 2019/6/29 21:37
 * @Description 磁盘日志流记录器
 */
@Slf4j
@AllArgsConstructor
public abstract class DiskLogStream implements LogStream {

    protected static final String LOG_FILE_PREFIX = "RELAY-JOB-LOG-";

    protected static final String LOG_FILE_SUFFIX = ".log";

    // 日志根路径
    private String logRootPath;

    public void init() {
        if (log.isInfoEnabled()) {
            log.info("Disk log stream start initialization, log root path: {}", this.logRootPath);
        }

        File file = new File(logRootPath);
        if (!file.exists()) {
            if (!file.mkdirs()) {
                throw new IllegalArgumentException("Can't create relay job endpoint root log dictionary.(" + logRootPath + ")");
            }
        }

        if (log.isInfoEnabled()) {
            log.info("Disk log stream initialization completed.");
        }
    }

    @Override
    public void append(String logId, String message) {
        try {
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(getLogFile(logId, true), true)));
            message = (message == null ? "" : message).concat(System.lineSeparator());
            writer.write(message);
            writer.flush();
            writer.close();
        } catch (Exception e) {
            log.error("Write relay job log file error.", e);
        }
    }

    @Override
    public List<String> read(String logId, long startLine, long endLine) {
        return this.readLine(logId, startLine, endLine);
    }

    @Override
    public long getTotalRow(String jobId) {
        File file = getLogFile(jobId, false);
        if (file == null || !file.exists()) {
            return 0L;
        }
        try (LineNumberReader reader = new LineNumberReader(new FileReader(file))) {
            reader.skip(file.length());
            return reader.getLineNumber();
        } catch (Exception e) {
            throw new RelayJobLogException(e);
        }
    }

    @Override
    public void delete(String logId) {
        File logFile = getLogFile(logId, false);
        if (logFile != null && logFile.exists()) {
            logFile.delete();
        }
    }

    protected List<String> readLine(String logId, Long startLine, Long endLine) {
        if (startLine == null) {
            startLine = 0L;
        }
        if (endLine == null) {
            endLine = Long.MAX_VALUE;
        }
        Assert.state(startLine >= 0L, "The number of rows to read from must be greater than zero.");
        Assert.state(endLine >= 0L, "The number of read cut-off rows must be greater than zero.");

        File file = getLogFile(logId, false);
        if (file == null || !file.exists() || file.length() == 0L) {
            return Collections.emptyList();
        }
        try (LineNumberReader reader = new LineNumberReader(new FileReader(file))) {

            List<String> content = new LinkedList<>();
            long index = 0;
            String line;
            while ((line = reader.readLine()) != null) {
                if (++index >= startLine) {
                    content.add(line);
                }
                if (index > endLine) {
                    break;
                }
            }
            return content;
        } catch (Exception e) {
            throw new RelayJobLogException(e);
        }
    }

    protected File getLogFile(String logId, boolean autoCreate) {
        String pathname = new StringBuilder(logRootPath)
                .append(File.separator)
                .append(LOG_FILE_PREFIX)
                .append(logId)
                .append(LOG_FILE_SUFFIX).toString();
        File file = new File(pathname);
        if (autoCreate && !file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                log.error("Create relay job log file error, file path : " + pathname, e);
            }
        }
        return file;
    }

}
